<?php if (!defined('FIT_PATH')) exit('No direct script access allowed');
/**
 * @copyright 2009 - 2011 Bincent.com. All Rights Reserved.
 * @license http://www.apache.org/licenses/LICENSE-2.0
 * @package FitPHP
 * @subpackage library
 * 
 * @author Hongbin Hsu <hongbin.hsu@gmail.com> Initial.
 * @version $Id: library/xml.php 1.0 2010-09-18 16:52 hongbin.hsu $
 */
 
// ------------------------------------------------------------------------

class Library_Xml
{
	//----------------------------------------------------------
	
	public function __construct($isnormal = FALSE) {
		$this->isnormal = $isnormal;
		$this->parser = xml_parser_create('ISO-8859-1');
		xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
		xml_set_object($this->parser, $this);
		xml_set_element_handler($this->parser, 'open','close');
		xml_set_character_data_handler($this->parser, 'data');
	}
	
	//----------------------------------------------------------

	public function unserialize(&$xml) {
		$data = $this->parse($xml);
		$xml_parser->destruct();
		return $data;
	}
	
	//----------------------------------------------------------
	
	public function serialize($arr, $htmlon = FALSE, $level = 1) {
		$s = $level == 1 ? "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n<root>\r\n" : '';
		$space = str_repeat("\t", $level);
		foreach($arr as $k => $v) {
			if(!is_array($v)) {
				$s .= $space."<item id=\"$k\">".($htmlon ? '<![CDATA[' : '').$v.($htmlon ? ']]>' : '')."</item>\r\n";
			} else {
				$s .= $space."<item id=\"$k\">\r\n".$this->serialize($v, $htmlon, $level + 1).$space."</item>\r\n";
			}
		}
		$s = preg_replace("/([\x01-\x09\x0b-\x0c\x0e-\x1f])+/", ' ', $s);
		return $level == 1 ? $s."</root>" : $s;
	}
	
	//----------------------------------------------------------

	public function destruct() {
		xml_parser_free($this->parser);
	}
	
	//----------------------------------------------------------
	
	public function parse(&$data) {
		$this->document = array();
		$this->stack	= array();
		return xml_parse($this->parser, $data, true) && !$this->failed ? $this->document : '';
	}
	
	//----------------------------------------------------------
	
	public function open(&$parser, $tag, $attributes) {
		$this->failed = FALSE;
		if(!$this->isnormal) {
			if(isset($attributes['id']) && !is_string($this->document[$attributes['id']])) {
				$this->document  = &$this->document[$attributes['id']];
			} else {
				$this->failed = TRUE;
			}
		} else {
			if(!isset($this->document[$tag]) || !is_string($this->document[$tag])) {
				$this->document  = &$this->document[$tag];
			} else {
				$this->failed = TRUE;
			}
		}
		$this->stack[] = &$this->document;
		$this->last_opened_tag = $tag;
		$this->attrs = $attributes;
	}
	
	//----------------------------------------------------------
	
	public function data(&$parser, $data) {
		if($this->last_opened_tag != NULL) {
			$this->data = $data;
		} else {
			$this->data = '';
		}
	}
	
	//----------------------------------------------------------
	
	public function close(&$parser, $tag) {
		if($this->last_opened_tag == $tag) {
			$this->document = $this->data;
			$this->last_opened_tag = NULL;
		}
		array_pop($this->stack);
		if($this->stack) {
			$this->document = &$this->stack[count($this->stack)-1];
		}
	}
}